package com.course.web.component.base;

import com.course.web.model.HasID;
import com.vaadin.data.HasValue;
import com.vaadin.data.ValueProvider;
import com.vaadin.shared.Registration;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Grid;

import java.util.List;
import java.util.Optional;

/**
 * Created by Justin on 2017/5/24.
 */
public class BaseList<T extends HasID> extends CustomComponent {

    private final Grid<T> grid;
    private final HasValue<Integer> adapter;
    private Handler<T> handler;
    private List<T> items;
    private boolean required;

    public BaseList(Handler<T> handler) {
        this.grid = new Grid<>();
        this.adapter = new HasValueAdapter();
        this.handler = handler;
        grid.setSelectionMode(Grid.SelectionMode.SINGLE);
        grid.addItemClickListener(event -> click(event.getItem()));
        setCompositionRoot(grid);
        setSizeFull();
    }

    public BaseList() {
        this(null);
    }

    public void setHandler(Handler<T> handler) {
        this.handler = handler;
    }

    public void setItems(List<T> items) {
        if (items != null) {
            this.items = items;
            flush();
        }
    }

    public T getValue() {
        return grid.asSingleSelect().getValue();
    }

    public void setValue(T value) {
        grid.asSingleSelect().setValue(value);
    }

    public void setValue(int id) {
        if (id == 0) {
            deselect();
            return;
        }
        Optional<T> first = items.stream().filter(item -> item.getId() == id).findFirst();
        if (first.isPresent()) {
            setValue(first.get());
        } else {
            deselect();
        }
    }

    public void flush() {
        grid.setItems(items);
    }

    public void deselect() {
        grid.deselectAll();
    }

    public Grid.Column<T, ?> addColumn(ValueProvider<T, ?> provider, String caption) {
        return grid.addColumn(provider).setCaption(caption);
    }


    public HasValue<Integer> adapter() {
        return adapter;
    }

    private void click(T item) {
        if (handler == null || item == null) {
            return;
        }
        handler.onSelect(item);
    }

    public interface Handler<T> {

        void onSelect(T item);
    }

    private class HasValueAdapter implements HasValue<Integer> {

        @Override
        public void setValue(Integer value) {
            BaseList.this.setValue(value);
        }

        @Override
        public Integer getValue() {
            T value = BaseList.this.getValue();
            return value != null ? value.getId() : 0;
        }

        @Override
        public Registration addValueChangeListener(ValueChangeListener<Integer> listener) {
            return grid.asSingleSelect().addValueChangeListener(event -> {
                Component component = BaseList.this;
                int oldValue = event.getOldValue() != null ? event.getOldValue().getId() : 0;
                HasValue<Integer> hasValue = HasValueAdapter.this;
                boolean isUserOriginated = event.isUserOriginated();
                listener.valueChange(new ValueChangeEvent<>(component, hasValue, oldValue, isUserOriginated));
            });
        }

        @Override
        public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
            required = requiredIndicatorVisible;
        }

        @Override
        public boolean isRequiredIndicatorVisible() {
            return required;
        }

        @Override
        public void setReadOnly(boolean readOnly) {
            grid.asSingleSelect().setReadOnly(readOnly);
        }

        @Override
        public boolean isReadOnly() {
            return grid.asSingleSelect().isReadOnly();
        }
    }

}
